/*
*	title: thirdL.c
*
*	Code for the thirdL level of the distributed system.
*	This peace of code determines the sorting of a integer vector with 250 elements, 
*	passing it through the socket to the secondL server.
*	The 250 elements come from the leaf level connected through socket.
*
*	Date: 22/09/2013
*	Autors: Danilo Barbosa Porto , Henrique Alberto Rusa
*/

#include<sys/timeb.h>
#include <stdio.h>
#include <stdlib.h>
#include<errno.h>
#include "tcptoken.h"


#define LEAF_VECTOR 125 			// size of the vector received from the leafs
#define CONCATENATED_VECTOR 250		// concatenate two received vectors 125 in one of 250 and send over socket
#define RECEIVED_VECTOR 1000		// receives 1000 integers over socket


// function to compare two integers used on the qsort function call 
int comp (const void *a, const void *b);

// function to calculate the time interval of execution
float time_dif(struct timeb end, struct timeb start);

/*
*	Main function.
*	Parameters:	thirdL <PortNumberToLeaf> <PortNumberToSecondL> <HostServerSecondL> 
*/
int main (int argc, char *argv[]) {

	// variables to calculate the time interval
	struct timeb startConnecr,startConnecl,startClient;
	struct timeb endConnecr,endConnecl,endClient;
	struct timeb startSort,endSort;
	
	// arguments verification
	if ( argc < 3) {
		fprintf(stderr,"ERROR [%s] usage thirdL <PortNumberToLeaf> <PortNumberToSecondL> <HostServerSecondL>: %s \n",argv[0],strerror(errno));
		exit(0);
	}

	// getting port number from first and second argument
	int portno_leaf = atoi(argv[1]);
	int portno_secondl = atoi(argv[2]);
	
	/* 
	*	instances of the server to handle the two leaf connections 
	*	and a client to deal with the secondL connection.
	*/
	servtoken serv_2leafr,serv_2leafl;
	clientoken client_2second;
	
	// starting the servers of the leafs and the secondl´s client
	newServer( &serv_2leafl, portno_leaf );
	newServer( &serv_2leafr, portno_leaf + 1 );
	newClient( &client_2second, portno_secondl, argv[3] );

	// considering the code´s structure, we initiate the client connecting it to the above level server
	clientStart( &client_2second );
	ftime(&startClient);
	
	/* 
	*	connecting and receiving the vectors to concatenate.
	* 	Now we initiate the server, because it would interrupt the program until a connection has been made.
	*/ 
	serverStart( &serv_2leafl );
	ftime(&startConnecl);
	serverStart( &serv_2leafr );
	ftime(&startConnecr);
	
	/*  
	*	outputBuffer - buffer used to receive and send 250 integers to secondL
	*	middleOutBuffer - buffer used to point to the middle of the outoutBuffer
	*	storageBuffer - buffer used to store the original vector received
	*/
	int *outputBuffer, *inputBuffer;
	int *middleOutBuffer;
	int *storageBuffer;
	
	inputBuffer = (int *)malloc( RECEIVED_VECTOR * sizeof(int));
	outputBuffer = (int *)malloc(  CONCATENATED_VECTOR * sizeof(int));
	middleOutBuffer = &outputBuffer[LEAF_VECTOR];
	storageBuffer = (int *)malloc(RECEIVED_VECTOR * sizeof(int));
	
	/*
	* 	Our program receives data through both servers.
	*	Data received will be concatenated using two pointers 
	*	to the same vector.
	*	So we utilize a pointer on the middle of the bigger one
	*	to pass as a buffer to the second half of data.
	*/
	int r,l; r = l = 0;
	l = serverRead( &serv_2leafl, (void *)outputBuffer, sizeof(int) * LEAF_VECTOR);
	r = serverRead( &serv_2leafr, (void *)middleOutBuffer, sizeof(int) * LEAF_VECTOR);
	if(( r < 0)||( l < 0)) {
		fprintf(stderr,"ERROR [%s] server reading from socket: %s \n",argv[0],strerror(errno));
		exit(0);
	}

	// store the received vector
	memcpy( storageBuffer,outputBuffer,RECEIVED_VECTOR * sizeof(int) );
	
	// call to sort for the concatenated vector
	ftime(&startSort);
	qsort( outputBuffer, CONCATENATED_VECTOR, sizeof(int), &comp);
	ftime(&endSort);
	
	// send to the secondL server the concatenated vector
	int s = 0;
	s = clientWrite( &client_2second, (void *)outputBuffer, sizeof(int) * CONCATENATED_VECTOR );
	if( s < 0) {
		fprintf(stderr,"ERROR [$s] client writing on socket: %s \n",argv[0],strerror(errno));
		exit(0);
	}
	
	// receive the sorted vector from the secondL
	r = clientRead( &client_2second, (void *)inputBuffer, sizeof(int) * RECEIVED_VECTOR );
	if( r < 0) {
		fprintf(stderr,"ERROR [%s] client could not read the socket: %s \n",argv[0],strerror(errno));
		exit(0);
	}
	
	/*
	*	With the sorted vector at our buffer we initiate the transport
	*	to the leafs.
	*	We will use the servers allocated to write to the leafs.
	*/
	r = l = 0;
	l = serverWrite( &serv_2leafl, (void *)inputBuffer, sizeof(int) * RECEIVED_VECTOR);
	r = serverWrite( &serv_2leafr, (void *)inputBuffer, sizeof(int) * RECEIVED_VECTOR);
	if(( r < 0)||( l < 0)) {
		fprintf(stderr,"ERROR [%s] server reading from socket: %S \n",argv[0],strerror(errno));
		exit(0);
	}
	
	// Closing the instances of client and the servers used
	closeClient( &client_2second );
	ftime(&endClient);
	closeServer( &serv_2leafl );
	ftime(&endConnecl);
	closeServer( &serv_2leafr );
	ftime(&endConnecr);
	
	return 0;
}

// function to compare two integers used on the qsort function call 
int comp (const void *a, const void *b) {
	return ( *(int *)a - *(int *)b );
}

// function to calculate the time interval of execution
float time_dif(struct timeb end, struct timeb start) {
	float dif;
	return dif = (float)((end.time - start.time) + 0.001*(end.millitm - start.millitm));
}





























